package bg.tu.varna.pms.client;

import java.awt.EventQueue;
import java.security.InvalidParameterException;
import java.util.Arrays;
import java.util.Calendar;
import java.util.List;
import java.util.UUID;
import java.util.Vector;
import java.util.concurrent.CountDownLatch;
import org.omg.CORBA.portable.ApplicationException;
import org.omg.PortableInterceptor.SYSTEM_EXCEPTION;
import bg.tu.varna.pms.client.ServerReference.ResponseHandler;
import bg.tu.varna.pms.client.listener.UserEvent;
import bg.tu.varna.pms.model.ChatMessage;
import bg.tu.varna.pms.model.ChatRoom;
import bg.tu.varna.pms.model.Contact;
import bg.tu.varna.pms.model.ContactStatus;
import bg.tu.varna.pms.model.FileMessage;
import bg.tu.varna.pms.model.communication.ChatMessage.Delivery;
import bg.tu.varna.pms.model.communication.FriendshipMessage.Type;
import bg.tu.varna.pms.model.communication.LoginMessage;
import bg.tu.varna.pms.model.communication.SearchMessage;
import bg.tu.varna.pms.model.communication.SearchMessage.Response;
import bg.tu.varna.pms.model.communication.SyncMessage;
import bg.tu.varna.pms.model.communication.SyncMessage.OperationType;

public class UserContext {
	private final UUID mSessionID;
	private String mUsername;
	private String mNickname;
	private String mName, mSurname, mFamily;
	private Calendar mDateOfBirth;
	private ContactStatus mStatus;
	private String mStatusMessage;

	private List<Contact> mContacts;
	private List<ChatRoom> mChatRooms;

	private UserCache mCache;

	private Vector<UserEvent> mUserEventListeners;

	static {
		ServerReference.ResponseHandler<SyncMessage.Response> a = new ServerReference.ResponseHandler<SyncMessage.Response>() {
			@Override
			public void run() {}
			@Override
			public void handleResponse( bg.tu.varna.pms.model.communication.SyncMessage.Response response ) {}
			@Override
			public bg.tu.varna.pms.model.communication.SyncMessage.Response getResponse() {
				// TODO Auto-generated method stub
				return null;
			}
		};
	}

	UserContext( LoginMessage.Response response ) throws ApplicationException {
		mSessionID = response.getSessionID();
		mUsername = response.getUsername();
		mNickname = response.getNickname();
		mName = response.getName();
		mSurname = response.getSurname();
		mFamily = response.getFamily();
		mDateOfBirth = response.getDateOfBirth();
		mStatus = response.getStatus();
		mStatusMessage = response.getStatusMessage();

		mCache = new UserCache( mUsername.toLowerCase() );
	}

	public void addUserEventListener( UserEvent listener ) {
		if ( mUserEventListeners == null )
			mUserEventListeners = new Vector<UserEvent>();

		mUserEventListeners.addElement( listener );
	}

	public UUID getSessionID() {
		return mSessionID;
	}
	public String getUsername() {
		return mUsername;
	}
	public String getNickname() {
		return mNickname;
	}
	public String getName() {
		return mName;
	}
	public String getSurname() {
		return mSurname;
	}
	public String getFamily() {
		return mFamily;
	}
	public Calendar getDateOfBirth() {
		return mDateOfBirth;
	}
	public ContactStatus getStatus() {
		return mStatus;
	}
	public String getStatusMessage() {
		return mStatusMessage;
	}
	public UserContext setNickname( String nickname ) {
		mNickname = nickname;
		return this;
	}
	public UserContext setName( String name ) {
		mName = name;
		return this;
	}
	public UserContext setSurname( String surname ) {
		mSurname = surname;
		return this;
	}
	public UserContext setFamily( String family ) {
		mFamily = family;
		return this;
	}
	public UserContext setDateOfBirth( Calendar dateOfBirth ) {
		mDateOfBirth = dateOfBirth;
		return this;
	}
	public UserContext setStatus( ContactStatus status ) {
		mStatus = status;
		return this;
	}
	public UserContext setStatusMessage( String statusMessage ) {
		mStatusMessage = statusMessage;
		return this;
	}

	public void getContacts() {
		EventQueue.invokeLater( new Runnable() {
			@Override
			public void run() {
				try {
					Calendar vLastSync = mCache.getChatRoomsSync();
					mContacts = Arrays.asList( mCache.getContactList() );
					for ( Contact vContact : mContacts ) {
						vContact.setStatus( ContactStatus.Offline );
					}
					contactsModification( mContacts.toArray( new Contact[] {} ) );
					ServerReference.getInstance().queueMessage( 0, new SyncMessage.Request( SyncMessage.SyncType.ContactList, vLastSync ) );
				} catch ( ApplicationException e ) {
					e.printStackTrace( System.err );
					reportException( e );
				}
			}
		} );
	}
	public void getChatRooms() {}

	public void searchUsers( String username, String nickname, String name, String surname, String family, Calendar dateOfBirth ) {}
	public void searchUsers( UUID searchID, int page ) {}

	public void addUser( String username, String message ) {}
	public void acceptUser( String username ) {}
	public void declineUser( String username ) {}
	public void removeUser( String username ) {}

	public void crateChatRoom( final String[] usernames )
			throws InvalidParameterException {
		if ( usernames == null || usernames.length == 0 ) {
			throw new InvalidParameterException( "usernames" );
		} else {
			EventQueue.invokeLater( new Runnable() {
				@Override
				public void run() {
					ChatRoom vChatRoom = new ChatRoom( mUsername, usernames );
					if ( vChatRoom.isGroupChat() ) {
						// TODO send to server
					}
					for ( UserEvent vListener : mUserEventListeners ) {
						vListener.chatRoomModification( vChatRoom, OperationType.Add );
					}
				}
			} );
		}
	}
	public UUID sendChatMessage( ChatRoom chatRoom, String message ) {
		if ( message == null || message == "" ) {
			throw new InvalidParameterException( "message" );
		} else {
			final ChatMessage vMessage = new ChatMessage( chatRoom.getID(), mUsername, message );
			EventQueue.invokeLater( new Runnable() {
				@Override
				public void run() {}
			} );
			return vMessage.getMessageID();
		}
	}
	public UUID sendFileMessage( ChatRoom chatRoom, String filename ) {
		if ( filename == null || filename == "" ) {
			throw new InvalidParameterException( "filename" );
		} else {
			// final ChatMessage vMessage = new ChatMessage( chatRoom.getID(),
			// mUsername, filename );
			EventQueue.invokeLater( new Runnable() {
				@Override
				public void run() {}
			} );
			return null;
		}
	}

	private void searchUsersComplete( Response result ) {
		for ( UserEvent vListener : mUserEventListeners ) {
			vListener.searchUsersComplete( result );
		}
	}
	private void searchUsersError( ApplicationException e ) {
		for ( UserEvent vListener : mUserEventListeners ) {
			vListener.searchUsersError( e );
		}
	}
	private void contactsModification( Contact[] contacts ) {
		for ( UserEvent vListener : mUserEventListeners ) {
			vListener.contactsModification( contacts );
		}
	}
	private void contactModification( Contact contact, OperationType type ) {
		for ( UserEvent vListener : mUserEventListeners ) {
			vListener.contactModification( contact, type );
		}
	}
	private void contactModification( Contact contact, String message, Type type ) {
		for ( UserEvent vListener : mUserEventListeners ) {
			vListener.contactModification( contact, message, type );
		}
	}
	private void chatRoomsModification( ChatRoom[] chatRooms ) {
		for ( UserEvent vListener : mUserEventListeners ) {
			vListener.chatRoomsModification( chatRooms );
		}
	}
	private void chatRoomModification( ChatRoom chatRoom, OperationType type ) {
		for ( UserEvent vListener : mUserEventListeners ) {
			vListener.chatRoomModification( chatRoom, type );
		}
	}
	private void messageReceived( ChatRoom chatRoom, ChatMessage message ) {
		for ( UserEvent vListener : mUserEventListeners ) {
			vListener.messageReceived( chatRoom, message );
		}
	}
	private void messageSend( ChatRoom chatRoom, ChatMessage message ) {
		for ( UserEvent vListener : mUserEventListeners ) {
			vListener.messageSend( chatRoom, message );
		}
	}
	private void messageDelivered( ChatRoom chatRoom, ChatMessage message ) {
		for ( UserEvent vListener : mUserEventListeners ) {
			vListener.messageDelivered( chatRoom, message );
		}
	}
	private void fileReceived( ChatRoom chatRoom, FileMessage file ) {
		for ( UserEvent vListener : mUserEventListeners ) {
			vListener.fileReceived( chatRoom, file );
		}
	}
	private void fileSend( ChatRoom chatRoom, FileMessage file ) {
		for ( UserEvent vListener : mUserEventListeners ) {
			vListener.fileSend( chatRoom, file );
		}
	}
	private void fileDelivered( ChatRoom chatRoom, FileMessage file ) {
		for ( UserEvent vListener : mUserEventListeners ) {
			vListener.fileDelivered( chatRoom, file );
		}
	}
	private void fileProgress( ChatRoom chatRoom, FileMessage file, int progress ) {
		for ( UserEvent vListener : mUserEventListeners ) {
			vListener.fileProgress( chatRoom, file, progress );
		}
	}
	private void reportException( Exception e ) {
		for ( UserEvent vListener : mUserEventListeners ) {
			vListener.reportException( e );
		}
	}

	static class ResponseHandlerImpl<T> implements ServerReference.ResponseHandler<T> {
		protected T mResponse;
		protected final UserContext mUserContext;

		public ResponseHandlerImpl() {
			mUserContext = ApplicationContext.getApplicationContext().getUserContext();
		}

		@Override
		public void run() {
			while ( true ) {
				try {
					Thread.sleep( 10000 );
				} catch ( InterruptedException e ) {
					return;
				}
			}
		}

		@Override
		public void handleResponse( T response ) {
			mResponse = response;
		}

		@Override
		public T getResponse() {
			return mResponse;
		}

	}

	static class ResponseHandlerChatMessageRequest extends ResponseHandlerImpl<bg.tu.varna.pms.model.communication.ChatMessage.Request> {
		@Override
		public void handleResponse( bg.tu.varna.pms.model.communication.ChatMessage.Request response ) {
			super.handleResponse( response );
			// TODO Synchronize cache
			if ( response.getMessage().getSender().equalsIgnoreCase( mUserContext.mUsername ) ) {} else {
				for ( ChatRoom vChatRoom : mUserContext.mChatRooms ) {
					if ( vChatRoom.getID().equalsIgnoreCase( response.getMessage().getChatRoomID() ) ) {
						mUserContext.messageReceived( vChatRoom, response.getMessage() );
						return;
					}
				}
				try {
					mUserContext.messageReceived( new ChatRoom( response.getMessage().getChatRoomID() ), response.getMessage() );
				} catch ( ApplicationException e ) {
					e.printStackTrace( System.err );
					mUserContext.reportException( e );
				}
			}
		}
	}

	static class ResponseHandlerSearchMessageResponse extends ResponseHandlerImpl<SearchMessage.Response> {
		@Override
		public void handleResponse( bg.tu.varna.pms.model.communication.SearchMessage.Response response ) {
			super.handleResponse( response );
			mUserContext.searchUsersComplete( response );
		}
	}

}
